home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TPUG - Toronto PET Users Group
/
TPUG Users Group CD
/
TPUG Users Group CD.iso
/
AMIGA
/
(A)TB
/
(A)TBY.ADF
/
Soundzap
/
SoundZAP.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-19
|
14KB
|
539 lines
/************************/
/**SoundZAP Version 2.4**/
/************************/
/*
* This program was compiled with Matthew Dillon's DICE C compiler, which
* automatically opens and closes the Amiga libraries as they are needed.
* If your compiler does not do this you will have to Add the appropriate
* code (or get DICE!!).
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <stdio.h>
#include <iff/iff.h>
#include <iff/8svx.h>
#include "SoundZAP.h"
void main(int argc, char *argv[])
{
char comline[33];
struct options *Opt;
if (argc<2) GiveUsage();
if ((Opt=(UBYTE *)AllocMem(sizeof(struct options),MEMF_PUBLIC))==NULL)
CleanUp(Opt,5);
Opt->BuffSize = DEFAULT_SIZE;
Opt->FlipSign = FALSE;
Opt->KillChunk = FALSE;
Opt->SampRate = DEFAULT_RATE;
Opt->IFFOut = TRUE;
Opt->InType = UNKNOWN;
Opt->MuLaw = FALSE;
Opt->SampChk = TRUE;
Opt->Data = NULL;
Opt->Size = 0;
Opt->Bits = 8;
strcpy(Opt->inname,"");
strcpy(Opt->outname,"");
while (--argc > 0)
{
strcpy(comline,argv[argc]);
if (comline[0]=='-')
ProcessOpt(Opt,comline);
else
{
strcpy(Opt->outname,Opt->inname);
strcpy(Opt->inname,comline);
}
}
if (strlen(Opt->inname)==0)
GiveUsage();
if (strlen(Opt->outname)==0)
{
int l;
strcpy(Opt->outname,Opt->inname);
l=strlen(Opt->outname);
if(Opt->outname[l-4]=='.')
Opt->outname[l-4]='\0';
if(Opt->outname[l-3]=='.')
Opt->outname[l-3]='\0';
strcat(Opt->outname,".iff");
}
printf("Input File: %s\nOutput File: %s\n",Opt->inname,Opt->outname);
if (Opt->BuffSize!=0) printf("Buffer Size: %d bytes\n",Opt->BuffSize);
else printf("Allocating maximum buffer size.\n");
if(!Opt->SampChk)
printf("Sample Rate: %d samples per second\n",Opt->SampRate);
AnalyzeData(Opt);
CleanUp(Opt,0);
}
void GiveUsage()
{
printf("SoundZap v2.4\n");
printf("Usage: SoundZAP [<options>] SOURCE [DESTINATION]\n");
printf(" (actually, the options can appear anywhere)\n\n");
printf(" options: -w Output RAW data\n");
printf(" -s Toggle signed/unsigned output\n");
printf(" -n Don't create extra chunks in IFF output\n");
printf(" -f Assume input data is RAW\n");
printf(" -b<n> Use a buffer size of n kilobytes\n");
printf(" if n==0 then SoundZAP will try to\n");
printf(" allocate enough memory to convert\n");
printf(" the whole sample in one shot.\n");
printf(" -r<n> Change sample rate.\n");
printf(" where n is the sample rate or\n");
printf(" one of the built in values.\n");
printf("\nSee documentation for more info.\n");
printf("mrc113@psuvm.psu.edu\n");
exit(0);
}
void ProcessOpt(struct options *Opt, char com[])
{
int len;
ULONG n;
switch (com[1])
{
case 'w' : Opt->IFFOut=FALSE;
break;
case 's' : Opt->FlipSign=TRUE;
break;
case 'n' : Opt->KillChunk=TRUE;
break;
case 'f' : Opt->InType=RAW;
break;
case 'b' : len=strlen(com)-2;
if (len==0)
CleanUp(Opt,2);
Opt->BuffSize=(ULONG)atoi(com+2)*1024;
break;
case 'r' : len=strlen(com)-2;
if (len==0)
CleanUp(Opt,3);
if (len==1)
{
switch (com[2])
{
case '5' : Opt->SampRate=5696;
break;
case '7' : Opt->SampRate=7596;
break;
case '8' : Opt->SampRate=8000;
break;
case '2' : Opt->SampRate=22790;
break;
default : Opt->SampRate=11395;
}
}
else
{
n=(LONG)atoi(com+2);
if (n!=0) Opt->SampRate=n;
else Opt->SampRate=11395;
}
Opt->SampChk=FALSE;
break;
default : CleanUp(Opt,4);
}
}
void CleanUp(struct options *Opt, int Error)
{
if (Opt->Data) FreeMem(Opt->Data,Opt->BuffSize);
if (Opt) FreeMem(Opt,sizeof(struct options));
if (in) Close(in);
if (out) Close(out);
if (Error==0) exit(0);
else
{
printf("%s",ErrorMessages[Error]);
exit(20);
}
}
void AnalyzeData(struct options *Opt)
{
ULONG MagicWord;
char IsMac[8];
if ((in=(struct FileHandle *)Open(Opt->inname,MODE_OLDFILE))==NULL)
CleanUp(Opt,6);
if(Opt->BuffSize==0)
{
Seek(in,0,OFFSET_END);
Opt->BuffSize=Seek(in,0,OFFSET_BEGINNING);
}
if ((Opt->Data=(UBYTE *)AllocMem(Opt->BuffSize,MEMF_PUBLIC))==NULL)
CleanUp(Opt,5);
Read(in,&MagicWord,4);
if (Opt->InType==UNKNOWN)
{
if (MagicWord==0x2e736e64) /* '.snd' */
ConvertAU(Opt);
else if (MagicWord==0x464f524d) /* 'FORM' */
ConvertIFF(Opt);
else if (MagicWord==0x43726561) /* 'Crea' */
ConvertVOC(Opt);
else if (MagicWord==0x52494646) /* 'RIFF' */
ConvertWAV(Opt);
}
Seek(in,65,OFFSET_BEGINNING);
Read(in,IsMac,8);
if (!strcmp(IsMac,"FSSDSFX!"))
ConvertMAC(Opt);
GuidoCheck(Opt);
}
/* This routine is a modified version of Guido van Rossum's (guido@cwi.nl)
* 'whatsound' routine. It guesses the sound file type (signed/unsigned/mu-law)
* by checking how the values in the file are distributed. Thanks Guido!!
*/
void GuidoCheck(struct options *Opt)
{
LONG a,n,sum;
unsigned long bin[4];
int x;
BPTR op=Output();
if(Opt->FlipSign)
{
Seek(in,0,OFFSET_END);
Opt->Size=Seek(in,0,OFFSET_BEGINNING);
ConvertRaw(Opt);
}
printf("Input is RAW data file.\n");
for (a=0; a<4; a++)
bin[a]=0;
do
{
n=Read(in,Opt->Data,Opt->BuffSize);
for(a=0; a<n; a++)
bin[Opt->Data[a]/64]++;
}
while (n==Opt->BuffSize);
if(bin[2]==0 && bin[3]==0)
CleanUp(Opt,7);
x=((bin[0]+bin[3])*100)/(bin[1]+bin[2]);
if(x>=300)
Opt->FlipSign=FALSE;
else if ( x <= 33)
Opt->FlipSign=TRUE;
else if ( (x >= 50) && (x <= 200))
Opt->MuLaw=TRUE;
printf("Done.\n");
if(Opt->SampChk && Opt->MuLaw) Opt->SampRate=8000;
Seek(in,0,OFFSET_END);
Opt->Size=Seek(in,0,OFFSET_BEGINNING);
ConvertRaw(Opt);
}
void ConvertRaw(struct options *Opt)
{
LONG b_read,i,scale,b_written,total;
int max;
signed char logs[256];
BPTR op=Output();
if((out=(struct FileHandle *)Open(Opt->outname,MODE_NEWFILE))==NULL)
CleanUp(Opt,8);
if (Opt->IFFOut)
WriteIFFStuff(Opt);
if (Opt->MuLaw)
{
Write(op,"Building log tables...",22);
max=getscale(Opt);
maketable(logs,max);
printf("Done.\n");
if (Opt->InType==AU)
Seek(in,32,OFFSET_BEGINNING);
else
Seek(in,0,OFFSET_BEGINNING);
}
scale=Opt->Bits/8;
total=0;
do
{
b_read=Read(in,Opt->Data,Opt->BuffSize)/scale;
if(Opt->FlipSign)
for (i=0; i<b_read; i++)
Opt->Data[i] ^= 0x80;
else if(Opt->MuLaw)
for (i=0; i<b_read; i++)
Opt->Data[i]=logs[Opt->Data[i]];
else if(scale!=1)
for (i=0; i<b_read; i++)
Opt->Data[i]=Opt->Data[i*scale];
total+=b_read;
if (total > Opt->Size)
b_read-=total-Opt->Size;
b_written=Write(out,Opt->Data,b_read);
if(b_written!=b_read) CleanUp(Opt,10);
}
while(total < Opt->Size);
if(Opt->IFFOut)
Write(out,"\0\0\0",(4-total%4)&3);
CleanUp(Opt,0);
}
void WriteIFFStuff(struct options *Opt)
{
int i,s;
ChunkHeader Form, V8Hdr, Body, Auth, Anno;
printf("Output file is in IFF 8SVX format.\n");
Voice8Header V8H = {0,0,32,8363,1,0,Unity};
if (Opt->KillChunk)
s=0;
else s=68;
Form.ckID = FORM;
Form.ckSize = 40 + s + Opt->Size + ((4-(Opt->Size%4))&3);
Write(out,&Form,8);
i=ID_8SVX;
Write(out,&i,4);
if (!Opt->KillChunk)
{
Auth.ckID = ID_AUTH;
Auth.ckSize = 16;
Write(out,&Auth,8);
Write(out,Author,16);
Anno.ckID = ID_ANNO;
Anno.ckSize = 36;
Write(out,&Anno,8);
Write(out,Annotation,36);
}
V8Hdr.ckID = ID_VHDR;
V8Hdr.ckSize = 20;
Write(out,&V8Hdr,8);
V8H.oneShotHiSamples = Opt->Size;
V8H.samplesPerSec = Opt->SampRate;
Write(out,&V8H,20);
Body.ckID = ID_BODY;
Body.ckSize = Opt->Size + ((4-(Opt->Size%4))&3);
Write(out,&Body,8);
}
void ConvertVOC(struct options *Opt)
{
UBYTE c[2];
printf("Input is .VOC file\n");
if(Opt->SampChk)
{
Seek(in,30,OFFSET_BEGINNING);
Read(in,c,2);
if(c[1]!=0)
CleanUp(Opt,9);
Opt->SampRate=1000000/(256-c[0]);
}
Opt->FlipSign=TRUE;
Seek(in,0,OFFSET_END);
Opt->Size=Seek(in,0,OFFSET_BEGINNING)-32;
Seek(in,32,OFFSET_BEGINNING);
ConvertRaw(Opt);
}
void ConvertWAV(struct options *Opt)
{
printf("Input is .WAV file\n");
Opt->FlipSign=TRUE;
Seek(in,0,OFFSET_END);
Opt->Size=Seek(in,0,OFFSET_BEGINNING)-44;
Seek(in,44,OFFSET_BEGINNING);
ConvertRaw(Opt);
}
void ConvertMAC(struct options *Opt)
{
printf("Input is Macintosh sound file\n");
Opt->FlipSign=TRUE;
Seek(in,0,OFFSET_END);
Opt->Size=Seek(in,0,OFFSET_BEGINNING)-668;
Seek(in,128,OFFSET_BEGINNING);
ConvertRaw(Opt);
}
/* Thanks to Sean Connolly for sending me info on the .au sound format.*/
void ConvertAU(struct options *Opt)
{
ULONG i;
int q;
AUHeader AUHdr;
Seek(in,0,OFFSET_END);
Opt->Size=Seek(in,0,OFFSET_BEGINNING)-32;
Read(in,&AUHdr,sizeof(AUHdr));
switch (AUHdr.encoding)
{
case 1 : Opt->MuLaw=TRUE;
printf("Input is 16-bit u-lawed .au file.\n");
break;
case 2 : Opt->Bits=8;
printf("Input is 8-bit linear .au file.\n");
break;
case 3 : Opt->Bits=16;
Opt->Size/=2;
printf("Input is 16-bit linear .au file.\n");
break;
case 4 : Opt->Bits=24;
Opt->Size/=3;
printf("Input is 24-bit linear .au file.\n");
break;
case 5 : Opt->Bits=32;
Opt->Size/=4;
printf("Input is 32-bit linear .au file.\n");
break;
default : CleanUp(Opt,9);
break;
}
if (Opt->SampChk)
Opt->SampRate=AUHdr.sample_rate;
ConvertRaw(Opt);
}
void ConvertIFF(struct options *Opt)
{
ULONG ThisID,ChunkSize,tmp;
LONG size,bytes;
Voice8Header V8H;
printf("Input file is in IFF 8SVX format.\n");
Seek(in,0,OFFSET_END);
if((size=Seek(in,0,OFFSET_BEGINNING)) > 50)
{
Read(in,&ThisID,4);
Read(in,&tmp,4);
if((tmp+8) == size)
{
do bytes=Read(in,&ThisID,4);
while ((bytes==4) && (ThisID!=ID_VHDR));
if(bytes==4)
{
Read(in,&tmp,4);
Read(in,&V8H,20);
if (Opt->SampChk)
Opt->SampRate=V8H.samplesPerSec;
do bytes=Read(in,&ThisID,4);
while ((bytes==4) && (ThisID!=ID_BODY));
if(bytes==4)
{
Read(in,&Opt->Size,4);
ConvertRaw(Opt);
}
}
}
}
CleanUp(Opt,11);
}
/*--------------------------------------------------------------------------*
* The following routine was extracted from posting by Brian Foley. *
* Brian Foley email: bfoley@greatlakes.Central.Sun.COM *
* Systems Engineer smail: 1000 Town Center *
* Sun Microsystems Suite 1700 *
* GreatLakes Region Southfield, MI 48075 (313) 352-7070 *
*--------------------------------------------------------------------------*/
int ulaw2linear(unsigned char ulawbyte)
{
static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
int sign, exponent, mantissa, sample;
ulawbyte = ~ulawbyte;
sign = ulawbyte & 0x80;
exponent = (ulawbyte >> 4) & 0x07;
mantissa = ulawbyte & 0x0F;
sample = (exp_lut[exponent] + (mantissa << (exponent + 3)));
if ( sign ) sample = -sample;
return sample;
}
int getscale(struct options *Opt)
{
int count, max = 0, i;
do
{
count = Read(in, Opt->Data, Opt->BuffSize);
for ( i = 0; i < count; i++ )
max = MAX(abs(ulaw2linear(Opt->Data[i])), max);
}
while ( count == Opt->BuffSize );
return max;
}
void maketable(signed char *logs, int max)
{
int i, c, d;
for ( i = 0; i < 256; i++ )
{
c = ( ulaw2linear(i) * ulaw2linear(0) ) / max;
d = abs(c) & 0xFF;
if ( d > 0x7F )
if ( c > 0 )
logs[i] = (signed char) ( c / 256 + 1 );
else
logs[i] = (signed char) ( c / 256 - 1 );
else
logs[i] = (signed char) ( c / 256 );
}
}